module Multiplier(
  iClk, // input clock
  iReset, // reset signal
  iReady, // indicates inputs are ready
  oDone, // indicates that the result is ready
  iMultiplier, // 8-bit multiplier [7:0]
  iMultiplicand, // 8-bit multiplicand [7:0]
  oProduct // 16-bit product [15:0]
);

  input iClk, iReset, iReady;
  input [7:0] iMultiplier, iMultiplicand;
  output [15:0] oProduct;
  output oDone;
  
  wire [15:0]tProduct0,tProduct1,tProduct2,tProduct3,tProduct4,tProduct5,tProduct6,tProduct7,tProduct8;
  wire [7:0]outputmux1,outputmux2,outputmux3,outputmux4,outputmux5,outputmux6,outputmux7,outputmux8;
  wire [7:0]outputFA1,outputFA2,outputFA3,outputFA4,outputFA5,outputFA6,outputFA7,outputFA8;
  wire outputFA_Cout1,outputFA_Cout2,outputFA_Cout3,outputFA_Cout4,outputFA_Cout5,outputFA_Cout6,outputFA_Cout7,outputFA_Cout8;
  wire [15:0]outputLink1,outputLink2,outputLink3,outputLink4,outputLink5,outputLink6,outputLink7,outputLink8;
  wire [7:0]wMultiplier;
  wire [7:0]wMultiplicand;
  wire [7:0]wSignedMultiplier;
  wire [7:0]wSignedMultiplicand;
  wire [7:0]wMPL, wMPC;
  wire [7:0]wMplicandS, wMplierS;
  wire wMplierC, wMplicandC;
  wire wsign;
  wire [15:0]woProduct, wmoProduct, woPro;
  wire wmoPC;

  Register_8bit Reg1(iMultiplier, iReset, iReady, iClk, wMultiplier);  
  Register_8bit Reg2(iMultiplicand, iReset, iReady, iClk, wMultiplicand);
  xor x1(wsign, wMultiplier[7], wMultiplicand[7]);
  
  xor x10(wSignedMultiplier[0], wMultiplier[7], wMultiplier[0]);
  xor x11(wSignedMultiplier[1], wMultiplier[7], wMultiplier[1]);
  xor x12(wSignedMultiplier[2], wMultiplier[7], wMultiplier[2]);
  xor x13(wSignedMultiplier[3], wMultiplier[7], wMultiplier[3]);
  xor x14(wSignedMultiplier[4], wMultiplier[7], wMultiplier[4]);
  xor x15(wSignedMultiplier[5], wMultiplier[7], wMultiplier[5]);
  xor x16(wSignedMultiplier[6], wMultiplier[7], wMultiplier[6]);
  xor x17(wSignedMultiplier[7], wMultiplier[7], wMultiplier[7]);
  
  Full_Adder_8bit FA00(wSignedMultiplier, 8'b00000001, wMplierS, wMplierC);
  Mux_2x1_8bit MUX00(wSignedMultiplier,wMplierS,wMultiplier[7],wMPL);
  
  xor x20(wSignedMultiplicand[0], wMultiplicand[7], wMultiplicand[0]);
  xor x21(wSignedMultiplicand[1], wMultiplicand[7], wMultiplicand[1]);
  xor x22(wSignedMultiplicand[2], wMultiplicand[7], wMultiplicand[2]);
  xor x23(wSignedMultiplicand[3], wMultiplicand[7], wMultiplicand[3]);
  xor x24(wSignedMultiplicand[4], wMultiplicand[7], wMultiplicand[4]);
  xor x25(wSignedMultiplicand[5], wMultiplicand[7], wMultiplicand[5]);
  xor x26(wSignedMultiplicand[6], wMultiplicand[7], wMultiplicand[6]);
  xor x27(wSignedMultiplicand[7], wMultiplicand[7], wMultiplicand[7]);
  
  Full_Adder_8bit FA01(wSignedMultiplicand, 8'b00000001, wMplicandS, wMplicandC);
  Mux_2x1_8bit MUX01(wSignedMultiplicand,wMplicandS,wMultiplicand[7],wMPC);
  
  Link L0(8'b00000000, wMPL, tProduct0);
  
  //First Loop
  Mux_2x1_8bit M1(8'b00000000, wMPC, tProduct0[0], outputmux1);
  Full_Adder_8bit FA1(tProduct0[15:8], outputmux1, outputFA1, outputFA_Cout1);
  Link L1(outputFA1, tProduct0[7:0], outputLink1);
  Shifter S1(outputLink1, tProduct1);
  
  //Second Loop
  Mux_2x1_8bit M2(8'b00000000, wMPC, tProduct1[0], outputmux2);
  Full_Adder_8bit FA2(tProduct1[15:8], outputmux2, outputFA2, outputFA_Cout2);
  Link L2(outputFA2, tProduct1[7:0], outputLink2);
  Shifter S2(outputLink2, tProduct2);
  
  //Thrid Loop
  Mux_2x1_8bit M3(8'b00000000, wMPC, tProduct2[0], outputmux3);
  Full_Adder_8bit FA3(tProduct2[15:8], outputmux3, outputFA3, outputFA_Cout3);
  Link L3(outputFA3, tProduct2[7:0], outputLink3);
  Shifter S3(outputLink3, tProduct3);
  
  //Fourth Loop
  Mux_2x1_8bit M4(8'b00000000, wMPC, tProduct3[0], outputmux4);
  Full_Adder_8bit FA4(tProduct3[15:8], outputmux4, outputFA4, outputFA_Cout4);
  Link L4(outputFA4, tProduct3[7:0], outputLink4);
  Shifter S4(outputLink4, tProduct4);
  
  //Fifth Loop
  Mux_2x1_8bit M5(8'b00000000, wMPC, tProduct4[0], outputmux5);
  Full_Adder_8bit FA5(tProduct4[15:8], outputmux5, outputFA5, outputFA_Cout5);
  Link L5(outputFA5, tProduct4[7:0], outputLink5);
  Shifter S5(outputLink5, tProduct5);
  
  //Sixth Loop
  Mux_2x1_8bit M6(8'b00000000, wMPC, tProduct5[0], outputmux6);
  Full_Adder_8bit FA6(tProduct5[15:8], outputmux6, outputFA6, outputFA_Cout6);
  Link L6(outputFA6, tProduct5[7:0], outputLink6);
  Shifter S6(outputLink6, tProduct6);
  
  //Seventh Loop
  Mux_2x1_8bit M7(8'b00000000, wMPC, tProduct6[0], outputmux7);
  Full_Adder_8bit FA7(tProduct6[15:8], outputmux7, outputFA7, outputFA_Cout7);
  Link L7(outputFA7, tProduct6[7:0], outputLink7);
  Shifter S7(outputLink7, tProduct7);
  
  //Eightth Loop
  Mux_2x1_8bit M8(8'b00000000, wMPC, tProduct7[0], outputmux8);
  Full_Adder_8bit FA8(tProduct7[15:8], outputmux8, outputFA8, outputFA_Cout8);
  Link L8(outputFA8, tProduct7[7:0], outputLink8);
  Shifter S8(outputLink8, tProduct8);
  xor x30(woProduct[0], wsign, tProduct8[0]);
  xor x31(woProduct[1], wsign, tProduct8[1]);
  xor x32(woProduct[2], wsign, tProduct8[2]);
  xor x33(woProduct[3], wsign, tProduct8[3]);
  xor x34(woProduct[4], wsign, tProduct8[4]);
  xor x35(woProduct[5], wsign, tProduct8[5]);
  xor x36(woProduct[6], wsign, tProduct8[6]);
  xor x37(woProduct[7], wsign, tProduct8[7]);
  xor x38(woProduct[8], wsign, tProduct8[8]);
  xor x39(woProduct[9], wsign, tProduct8[9]);
  xor x310(woProduct[10], wsign, tProduct8[10]);
  xor x311(woProduct[11], wsign, tProduct8[11]);
  xor x312(woProduct[12], wsign, tProduct8[12]);
  xor x313(woProduct[13], wsign, tProduct8[13]);
  xor x314(woProduct[14], wsign, tProduct8[14]);
  assign woProduct[15]=wsign;
  Full_Adder_16bit FA16(woProduct, 16'b0000000000000001, wmoProduct, wmoPC);
  Mux_2x1_16bit M16(woProduct, wmoProduct, wsign, woPro);
  assign oProduct=woPro;
  
  assign oDone=1'b1;

endmodule

module Half_Adder(s, c, a, b);
  input a, b;
  output s, c;
  
  xor x1(s, a, b);
  and a1(c, a, b);
endmodule

module Full_Adder(S, C_out, C_in, A, B);
  input A, B, C_in;
  output S, C_out;
  wire w1, w2;
  
  Half_Adder H1(w1, w2, A, B);
  Half_Adder H2(S, w3, w1, C_in);
  or o1(C_out, w3, w2);  
endmodule

module Full_Adder_8bit(A, B, S, C_out);
  
  input [7:0] A, B;
  output [7:0] S;
  output C_out;
  wire [7:0] w;
  
  Full_Adder F0(S[0], w[0], 1'b0, A[0], B[0]);
  Full_Adder F1(S[1], w[1], w[0], A[1], B[1]);
  Full_Adder F2(S[2], w[2], w[1], A[2], B[2]);
  Full_Adder F3(S[3], w[3], w[2], A[3], B[3]);
  Full_Adder F4(S[4], w[4], w[3], A[4], B[4]);
  Full_Adder F5(S[5], w[5], w[4], A[5], B[5]);
  Full_Adder F6(S[6], w[6], w[5], A[6], B[6]);
  Full_Adder F7(S[7], w[7], w[6], A[7], B[7]);
  
  assign C_out=w[7];
  
endmodule

module Full_Adder_16bit(A, B, S, C_out);
  
  input [15:0] A, B;
  output [15:0] S;
  output C_out;
  wire [15:0] w;
  
  Full_Adder F0(S[0], w[0], 1'b0, A[0], B[0]);
  Full_Adder F1(S[1], w[1], w[0], A[1], B[1]);
  Full_Adder F2(S[2], w[2], w[1], A[2], B[2]);
  Full_Adder F3(S[3], w[3], w[2], A[3], B[3]);
  Full_Adder F4(S[4], w[4], w[3], A[4], B[4]);
  Full_Adder F5(S[5], w[5], w[4], A[5], B[5]);
  Full_Adder F6(S[6], w[6], w[5], A[6], B[6]);
  Full_Adder F7(S[7], w[7], w[6], A[7], B[7]);
  Full_Adder F8(S[8], w[8], w[7], A[8], B[8]);
  Full_Adder F9(S[9], w[9], w[8], A[9], B[9]);
  Full_Adder F10(S[10], w[10], w[9], A[10], B[10]);
  Full_Adder F11(S[11], w[11], w[10], A[11], B[11]);
  Full_Adder F12(S[12], w[12], w[11], A[12], B[12]);
  Full_Adder F13(S[13], w[13], w[12], A[13], B[13]);
  Full_Adder F14(S[14], w[14], w[13], A[14], B[14]);
  Full_Adder F15(S[15], w[15], w[14], A[15], B[15]);
  
  assign C_out=w[15];
  
endmodule
  
module Mux_2x1_8bit(i0, i1, sel, out);
  
  input [7:0] i0, i1;
  input sel;
  output [7:0] out;
  wire [7:0] w1, w2;
  
  and a10(w1[0], ~sel, i0[0]);
  and a11(w1[1], ~sel, i0[1]);
  and a12(w1[2], ~sel, i0[2]);
  and a13(w1[3], ~sel, i0[3]);
  and a14(w1[4], ~sel, i0[4]);
  and a15(w1[5], ~sel, i0[5]);
  and a16(w1[6], ~sel, i0[6]);
  and a17(w1[7], ~sel, i0[7]);
  
  and a20(w2[0], sel, i1[0]);
  and a21(w2[1], sel, i1[1]);
  and a22(w2[2], sel, i1[2]);
  and a23(w2[3], sel, i1[3]);
  and a24(w2[4], sel, i1[4]);
  and a25(w2[5], sel, i1[5]);
  and a26(w2[6], sel, i1[6]);
  and a27(w2[7], sel, i1[7]);
  
  or o7(out[7], w1[7], w2[7]);
  or o6(out[6], w1[6], w2[6]);
  or o5(out[5], w1[5], w2[5]);
  or o4(out[4], w1[4], w2[4]);
  or o3(out[3], w1[3], w2[3]);
  or o2(out[2], w1[2], w2[2]);
  or o1(out[1], w1[1], w2[1]);
  or o0(out[0], w1[0], w2[0]);
  
endmodule

module Mux_2x1_16bit(i0, i1, sel, out);
  
  input [15:0] i0, i1;
  input sel;
  output [15:0] out;
  wire [15:0] w1, w2;
  
  and a10(w1[0], ~sel, i0[0]);
  and a11(w1[1], ~sel, i0[1]);
  and a12(w1[2], ~sel, i0[2]);
  and a13(w1[3], ~sel, i0[3]);
  and a14(w1[4], ~sel, i0[4]);
  and a15(w1[5], ~sel, i0[5]);
  and a16(w1[6], ~sel, i0[6]);
  and a17(w1[7], ~sel, i0[7]);
  and a18(w1[8], ~sel, i0[8]);
  and a19(w1[9], ~sel, i0[9]);
  and a110(w1[10], ~sel, i0[10]);
  and a111(w1[11], ~sel, i0[11]);
  and a112(w1[12], ~sel, i0[12]);
  and a113(w1[13], ~sel, i0[13]);
  and a114(w1[14], ~sel, i0[14]);
  and a115(w1[15], ~sel, i0[15]);
  
  and a20(w2[0], sel, i1[0]);
  and a21(w2[1], sel, i1[1]);
  and a22(w2[2], sel, i1[2]);
  and a23(w2[3], sel, i1[3]);
  and a24(w2[4], sel, i1[4]);
  and a25(w2[5], sel, i1[5]);
  and a26(w2[6], sel, i1[6]);
  and a27(w2[7], sel, i1[7]);
  and a28(w2[8], sel, i1[8]);
  and a29(w2[9], sel, i1[9]);
  and a210(w2[10], sel, i1[10]);
  and a211(w2[11], sel, i1[11]);
  and a212(w2[12], sel, i1[12]);
  and a213(w2[13], sel, i1[13]);
  and a214(w2[14], sel, i1[14]);
  and a215(w2[15], sel, i1[15]);
  
  or o15(out[15], w1[15], w2[15]);
  or o14(out[14], w1[14], w2[14]);
  or o13(out[13], w1[13], w2[13]);
  or o12(out[12], w1[12], w2[12]);
  or o11(out[11], w1[11], w2[11]);
  or o10(out[10], w1[10], w2[10]);
  or o9(out[9], w1[9], w2[9]);
  or o8(out[8], w1[8], w2[8]);
  or o7(out[7], w1[7], w2[7]);
  or o6(out[6], w1[6], w2[6]);
  or o5(out[5], w1[5], w2[5]);
  or o4(out[4], w1[4], w2[4]);
  or o3(out[3], w1[3], w2[3]);
  or o2(out[2], w1[2], w2[2]);
  or o1(out[1], w1[1], w2[1]);
  or o0(out[0], w1[0], w2[0]);
  
endmodule

module Mux_4x1(i0, i1, i2, i3, sel, out);
  input i0, i1, i2, i3;
  input [1:0] sel;
  output out;
  wire w0, w1, w2, w3;
  
  and a0(w0, ~sel[1], ~sel[0], i0);
  and a1(w1, ~sel[1], sel[0], i1);
  and a2(w2, sel[1], ~sel[0], i2);
  and a3(w3, sel[1], sel[0], i3);
  or o1(out, w0, w1, w2, w3);
  
endmodule

module Link(i0, i1, out);
  
  input [7:0] i0, i1;
  output [15:0] out;
  
  assign out[15:8] = i0[7:0];
  assign out[7:0] = i1[7:0];
  
endmodule

module Shifter(i, out);
  
  input [15:0] i;
  output [15:0] out;
  
  assign out[14:0] = i[15:1];
  assign out[15] = 1'b0;
  
endmodule
/*
module SR_Latch(S, R, Q1, Q2);

  input S, R;
  output Q1, Q2;
  wire w1, w2;
  
  nand n1(w1, S, w2);
  nand n2(w2, R, w1);
  
  assign Q1 = w2;
  assign Q2 = w1;

endmodule

module D_FlipFlop(D, clk, Q1, Q2);
  
  input D, clk;
  output Q1, Q2;
  wire w11, w12, w21, w22, w31, w32, w;
  
  SR_Latch SR1(w22, clk, w11, w12);
  and a1(w, clk, w12);
  SR_Latch SR2(w, D, w21, w22);
  SR_Latch SR3(w12, w21, w31, w32);
  
  assign Q1=w31;
  assign Q2=w32;
  
endmodule

module Register(wdata, rst, write, clk, rdata);
  input wdata, rst, write, clk;
  output rdata;
  wire [1:0] sel;
  wire w1, w2, w3;
  assign sel[1]=~rst;
  assign sel[0]=write;
  
  Mux_4x1 M1(w2, wdata, 1'b0, 1'b0, sel, w1);
  D_FlipFlop DF1(w1, clk, w2, w3);
  
  assign rdata=w2;
  
endmodule

module Register_8bit(wdata, rst, write, clk, rdata);
  input [7:0] wdata;
  input rst, clk, write;
  output [7:0] rdata;
  
  Register R0(wdata[0], rst, write, clk, rdata[0]);
  Register R1(wdata[1], rst, write, clk, rdata[1]);
  Register R2(wdata[2], rst, write, clk, rdata[2]);
  Register R3(wdata[3], rst, write, clk, rdata[3]);
  Register R4(wdata[4], rst, write, clk, rdata[4]);
  Register R5(wdata[5], rst, write, clk, rdata[5]);
  Register R6(wdata[6], rst, write, clk, rdata[6]);
  Register R7(wdata[7], rst, write, clk, rdata[7]);
  
endmodule
*/
